home *** CD-ROM | disk | FTP | other *** search
- ideal
- model large ; Replace this w/ whatever model your using
- p286 ; This code was written for 286+ machines
- jumps ; Allows far conditional jumps in 286 code
-
- assume ds:gus_data,cs:gus
-
- public guslib
-
- ; Our variables are stored in our own segment for portability...
-
- segment gus_data private
- gus_string db 'ULTRASND=',0
-
- base_port dw ?
- gf1_page dw ?
- gf1_register dw ?
- gf1_data_low dw ?
- gf1_data_high dw ?
- irq_status dw ?
- timer_control dw ?
- timer_data dw ?
- dram dw ?
- mixer dw ?
- irq_dma_control dw ?
- register_controls dw ?
- mixer_controls dw ?
-
- play_back_dma db ?
- play_back_dma_mask db ?
- gf1_irq db ?
- gf1_irq_mask db ?
- midi_irq db ?
- midi_irq_mask db ?
-
- irq_control db 8,15,12,11,7,3,5,2,0
- dma_control db 6,7,6,5,3,1,0
- dma_channels db 7 dup (00h)
- db 0ah,0ch,02h,03h,0bh,83h,0ah
- db 7 dup (00h)
- db 0ah,0ch,06h,07h,0bh,82h,0ah
- db 7 dup (00h)
- db 0d4h,0d8h,0c4h,0c6h,0d6h,8bh,0d4h
- db 0d4h,0d8h,0c8h,0cah,0d6h,89h,0d4h
- db 0d4h,0d8h,0cch,0ceh,0d6h,8ah,0d4h
-
- initialization db ?
- voice db 00h
- max_voices db 14h
- divisor dw 0000h
- d1 db ?
- d2 db ?
-
- old_ISR1 dd ?
- old_ISR2 dd ?
- old_flags dw ?
- irq_source db ?
- irq_voice db ?
- old_voice db ?
-
- dma_send dw 0000h
- dma_pos_high db 00h
- dma_pos_low dw 0000h
- dma_size_high db 00h
- dma_size_low dw 0000h
- dma_busy db 00h
- dma_wait db 00h
- dram_addr dw 0000h
-
-
- gus_functions dw offset init_gus
- dw offset deinit_gus
- dw offset poke
- dw offset peek
- dw offset set_active
- dw offset download_sound
- dw offset dma_status
- dw offset set_volume
- dw offset set_freq
- dw offset set_loop
- dw offset set_start
- dw offset set_end
- dw offset play_voice
- dw offset voice_status
- dw offset stop_voice
- dw offset read_8bit_reg
- dw offset write_8bit_reg
- dw offset read_16bit_reg
- dw offset write_16bit_reg
-
- lc db '0'
- pos dw 3840
- ends gus_data
-
- segment gus public
- proc value16 near
- push ax bx di es
- mov bx,0b800h
- mov es,bx
- mov al,[lc]
- mov di,[pos]
- mov [es:di],al
- inc [lc]
- cmp [lc],'9'+1
- jnz nu
- mov [lc],'0'
- nu: add [pos],2
- cmp [pos],4000
- jnz nu2
- mov [pos],3840
- nu2: pop es di bx ax
- ret
- endp value16
-
-
- proc guslib far
- cmp bx,12h
- jnc No_Func
- push ds
- push ax
- mov ax,gus_data
- mov ds,ax
- pop ax
- shl bx,1
- add bx,offset gus_functions
- call [word ptr ds:bx]
- pop ds
- No_Func: ret
- endp guslib
-
- proc delay near
- push cx dx ax
- mov cx,7
- mov dx,[base_port]
- d_lp1: in al,dx
- loop d_lp1
- pop ax dx cx
- ret
- endp delay
-
- proc read_8bit_reg near
- push dx
- pushf
- cli
- mov dx,[gf1_register]
- cmp al,0fh
- jnc no_spc
- add al,80h
- no_spc: out dx,al
- add dx,2
- in al,dx
- popf
- pop dx
- ret
- endp read_8bit_reg
-
- proc read_16bit_reg near
- push dx
- pushf
- cli
- mov dx,[gf1_register]
- cmp al,0fh
- jnc no_spc2
- add al,80h
- no_spc2: out dx,al
- inc dx
- in ax,dx
- popf
- pop dx
- ret
- endp read_16bit_reg
-
- proc write_8bit_reg near
- push dx
- push ax
- pushf
- cli
- mov dx,[gf1_register]
- out dx,al
- add dx,2
- mov al,ah
- out dx,al
- call delay
- out dx,al
- popf
- pop ax
- pop dx
- ret
- endp write_8bit_reg
-
- proc write_16bit_reg near
- push dx
- push ax
- pushf
- cli
- mov dx,[gf1_register]
- out dx,al
- inc dx
- mov ax,cx
- out dx,ax
- call delay
- out dx,ax
- popf
- pop ax
- pop dx
- ret
- endp write_16bit_reg
-
- proc poke near ; si=high di=low al=value
- pushf
- push dx
- push ax
- cli
- mov dx,[gf1_register]
- mov al,43h
- out dx,al
- inc dx
- mov ax,di
- out dx,ax
- dec dx
- mov al,44h
- out dx,al
- inc dx
- inc dx
- mov ax,si
- out dx,al
- add dx,2
- pop ax
- out dx,al
- call delay
- out dx,al
- pop dx
- popf
- ret
- endp poke
-
- proc peek near ; ah=voice si=high di=low al=return value
- push dx
- mov dx,[gf1_register]
- mov al,43h
- out dx,al
- inc dx
- mov ax,di
- out dx,ax
- dec dx
- mov al,44h
- out dx,al
- inc dx
- mov ax,si
- out dx,al
- add dx,3
- xor ax,ax
- in al,dx
- pop dx
- ret
- endp peek
-
- proc init_gus near
- mov [initialization],00h ; Don't need to deinit yet
- push es
- mov ah,51h ; Get the current PSP segment
- int 21h
- mov es,bx
- mov ax,[es:002ch] ; Find the environment strings
- mov es,ax
- mov si,offset gus_string
- mov di,0 ; Find the 'ULTRASND=' string
- env_lp1: mov al,[es:di]
- inc di
- cmp al,0
- jnz env_lp2
- mov al,[es:di+1]
- cmp al,0
- jz env_err
- rst_env: mov si,offset gus_string
- jmp env_lp1
- env_lp2: mov ah,[si]
- cmp ah,0
- jz env_ok
- cmp al,ah
- jnz rst_env
- inc si
- jmp env_lp1
- env_err: mov ax,1 ; String not found - Return code 1
- jmp init_done
- env_ok: xor ax,ax ; Found string - Process variable
- mov al,[es:di]
- sub al,'0'
- rol ax,4
- add ax,200h
- mov [base_port],ax ; Base Port (2x0h)
- add di,3
- mov al,[es:di]
- sub al,'0'
- mov [play_back_dma],al ; Play back DMA Channel
- add di,4
- mov al,[es:di]
- sub al,'0'
- mov [gf1_irq],al ; GF1 (Channel 1) Irq
- add di,2
- mov al,[es:di]
- sub al,'0'
- mov [midi_irq],al ; MIDI (Channel 2) Irq
- mov bx,[base_port] ; Set up I/O port address
- mov [mixer],bx ; Mix Control Register (2x0h)
- add bx,0bh
- mov [irq_dma_control],bx ; IRQ/DMA Control Register
- add bx,04h
- mov [register_controls],bx ; Register Controls
- add bx,0f3h
- mov [gf1_page],bx ; GF1 Page Selector
- inc bx
- mov [gf1_register],bx ; GF1/Global Register Selector
- inc bx
- mov [gf1_data_low],bx ; GF1/Global Data Low Byte
- inc bx
- mov [gf1_data_high],bx ; GF1/Global Data High Byte
- inc bx
- mov [mixer_controls],bx ; Mixer Conrols
- sub bx,100h
- mov [irq_status],bx ; Irq Status Register
- add bx,2
- mov [timer_control],bx ; Timer Control Register
- inc bx
- mov [timer_data],bx ; Timer Data
- add bx,0feh
- mov [dram],bx ; Direct DRAM I/O Register
-
- ; Environmental Variables are loaded... Procede w/ reseting the GUS
-
- mov ax,064ch ; Write 06h to Reset port (4ch)
- call write_8bit_reg
- mov ax,074ch ; Done w/ reset, now write 07h
- call write_8bit_reg
- mov al,4ch ; Read the reset port
- call read_8bit_reg
- mov bl,al
- mov ax,4 ; If it isn't 07h, then we've
- cmp bl,07h ; got a problem...
- jnz init_done
-
- ; Now, make sure the on board memory is there. This ensures that
- ; we acually have an ultrasound.
-
- mov al,33h
- mov si,0
- mov di,0
- call poke
- mov al,55h
- mov di,2
- call poke
- mov di,0
- call peek
- cmp al,33h
- jnz bad_dram
- mov di,2
- call peek
- cmp al,55h
- jnz bad_dram
-
- ; Now set up the on-board IRQs...
-
- mov dx,[mixer]
- mov al,4fh
- out dx,al
- xor cx,cx
- mov cl,[byte irq_control]
- mov si,1
- mov ah,[gf1_irq]
- rst_lp1: mov al,[byte irq_control+si]
- cmp ah,al
- jz rst_dn1
- inc si
- loop rst_lp1
- jmp bad_irq
- rst_dn1: dec cx
- mov [gf1_irq_mask],cl
- xor cx,cx
- mov cl,[byte irq_control]
- mov si,1
- mov ah,[midi_irq]
- rst_lp2: mov al,[byte irq_control+si]
- cmp ah,al
- jz rst_dn2
- inc si
- loop rst_lp2
- jmp bad_irq
- rst_dn2: dec cx
- mov [midi_irq_mask],cl
- mov dx,[irq_dma_control]
- mov bl,0
- mov al,[gf1_irq_mask]
- mov ah,[midi_irq_mask]
- cmp ah,al
- jnz ct_msk1
- mov ah,0
- mov bl,40h
- ct_msk1: rol ah,3
- or al,ah
- or al,bl
- out dx,al
- mov dx,[mixer]
- mov al,0fh
- out dx,al
- xor cx,cx
- mov cl,[byte dma_control]
- mov si,1
- mov ah,[play_back_dma]
- rst_lp3: mov al,[byte dma_control+si]
- cmp ah,al
- jz rst_dn3
- inc si
- loop rst_lp3
- jmp bad_dma
- rst_dn3: dec cx
- mov al,40h
- or al,cl
- mov dx,[irq_dma_control]
- out dx,al
- mov al,[play_back_dma]
- and al,3
- mov [play_back_dma_mask],al
-
- ; Set up IRQs and ISRs. From this point, deinitialization is a MUST!
-
- pushf
- cli
- mov ah,35h
- mov al,[gf1_irq]
- add al,8
- int 21h
- mov [word old_ISR1],bx
- mov [word old_ISR1+2],es
- mov ah,35h
- mov al,[midi_irq]
- add al,8
- int 21h
- mov [word old_ISR2],bx
- mov [word old_ISR2+2],es
- mov ah,25h
- mov al,[gf1_irq]
- add al,8
- push ds
- mov dx,offset gf1_ISR
- mov bx,seg gf1_ISR
- mov ds,bx
- int 21h
- pop ds
- mov ah,25h
- mov al,[midi_irq]
- add al,8
- push ds
- mov dx,offset midi_ISR ; Like we're using it here?!?
- mov bx,seg midi_ISR
- mov ds,bx
- int 21h
- pop ds
- in al,0a1h
- mov ah,al
- in al,21h
- mov [old_flags],ax
- mov bx,1
- mov dx,1
- mov cl,[gf1_irq]
- shl bx,cl
- mov cl,[midi_irq]
- shl dx,cl
- or bx,dx
- not bx
- and ax,bx
- out 21h,al
- mov al,ah
- out 0a1h,al
- popf
- mov [initialization],01h ; We MUST deinit now...
- mov dx,[mixer] ; Activate the GUS!
- mov al,09h
- out dx,al
- mov dx,[gf1_page] ; Select voice 0
- mov al,0
- out dx,al
- mov [voice],0
-
- mov ax,0
- jmp init_done
- bad_irq: mov ax,2
- jmp init_done
- bad_dma: mov ax,3
- jmp init_done
- bad_dram: mov ax,5
- jmp init_done
- init_done:
- pop es
- ret
- endp init_gus
-
- proc deinit_gus near
- pushf
- cli
- cmp [initialization],01h ; Did we initialize?
- jnz no_init
- mov ah,25h
- mov al,[gf1_irq]
- add al,8
- push ds
- lds dx,[dword old_ISR1]
- int 21h
- pop ds
- mov ah,25h
- mov al,[midi_irq]
- add al,8
- push ds
- lds dx,[dword old_ISR2]
- int 21h
- pop ds
- mov ax,[old_flags]
- out 21h,al
- mov al,ah
- out 0a1h,al
- no_init: mov dx,[mixer]
- mov al,0bh
- out dx,al
- popf
- ret
- endp deinit_gus
-
- proc dma_status near
- xor ax,ax
- mov al,[dma_busy]
- ret
- endp dma_status
-
- proc midi_ISR far ; Null ISR
- push ax
- mov al,20h
- out 20h,al
- pop ax
- iret
- endp midi_ISR
-
- proc set_active near
- push dx
- dec ax
- cmp al,13
- jnc nl13
- mov al,13
- nl13: cmp al,32
- jc lt32
- mov al,31
- lt32: mov [max_voices],al
- or al,0c0h
- mov ah,al
- mov al,0eh
- call write_8bit_reg
- xor bx,bx
- mov bl,[max_voices]
- inc bx
- mov ax,6bb8h
- mov dx,9
- div bx
- mov [divisor],ax
- pop dx
- ret
- endp set_active
-
- proc download_sound near ; es:si = source di = dram addr
- ; dx:ax = size cl = wait toggle
- cmp [dma_busy],1
- jz no_dma
- mov [dma_wait],cl
- mov [dma_size_high],dl
- mov [dma_size_low],ax
- mov [dram_addr],di
- mov ax,es
- rol ax,4
- and ax,15
- mov [dma_pos_high],al
- mov ax,es
- and ax,0fffh
- rol ax,4
- and si,0ff00h
- add ax,si
- mov [dma_pos_low],ax
- xor ax,ax
- sub ax,[dma_pos_low]
- mov [dma_send],ax
- cmp [dma_size_high],0
- jnz gt64k
- mov bx,[dma_size_low]
- cmp ax,bx
- jc gt64k
- mov [dma_send],bx
- mov [dma_size_low],0
- jmp go_dma
- gt64k: sub [dma_size_low],ax
- sbb [dma_size_high],0
- go_dma: xor ax,ax
- mov al,[play_back_dma]
- mov bx,7
- imul bx
- add ax,offset dma_channels
- mov si,ax
- xor dx,dx
- mov dl,[si]
- mov al,[play_back_dma_mask]
- or al,4
- out dx,al
- mov al,0
- mov dl,[si+1]
- out dx,al
- mov ax,[dma_pos_low]
- mov dl,[si+2]
- out dx,al
- mov al,ah
- out dx,al
- mov ax,[dma_send]
- dec ax
- mov dl,[si+3]
- out dx,al
- mov al,ah
- out dx,al
- mov al,[play_back_dma_mask]
- or al,48h
- mov dl,[si+4]
- out dx,al
- mov al,[dma_pos_high]
- mov dl,[si+5]
- out dx,al
- mov al,[play_back_dma_mask]
- mov dl,[si+6]
- out dx,al
- pushf
- cli
- mov al,42h
- mov cx,[dram_addr]
- call write_16bit_reg
- mov dx,[gf1_register]
- mov al,41h
- out dx,al
- add dx,2
- mov al,0a9h
- mov [dma_busy],1
- out dx,al
- popf
- cmp [dma_wait],0
- jz dma_dn
- dma_lp1: mov ah,6
- mov dl,0ffh
- int 21h
- jnz keyht1
- cmp [dma_busy],1
- jz dma_lp1
- mov ax,0
- dma_dn: ret
- keyht1: mov ax,1
- jmp dma_dn
- no_dma: mov ax,2
- jmp dma_dn
- endp download_sound
-
- proc gf1_ISR far ; Handles ALL GF1 interrupts
- push ax dx ds
- mov ax,gus_data
- mov ds,ax
- call delay
- call delay
- irq_lp1: mov dx,[irq_status]
- in al,dx
- cmp al,0
- jz gf1_dn
- test al,80h
- jz no_dma2
- mov dx,[gf1_register]
- mov al,41h
- out dx,al
- add dx,2
- in al,dx
- inc [dma_pos_high]
- mov [dma_pos_low],0
- cmp [dma_send],0
- jnz lt64k
- add [dram_addr],1000h
- dec [dma_size_high]
- jmp dma_go
- lt64k: mov ax,[dma_send]
- mov cl,4
- shr ax,cl
- add [dram_addr],ax
- dma_go: cmp [dma_size_high],0
- jz lt64k2
- mov [dma_send],0
- jmp dma_go2
- lt64k2: cmp [dma_size_low],0
- jz dma_dn2
- mov ax,[dma_size_low]
- mov [dma_send],ax
- dma_go2: mov ax,[dma_send]
- sub [dma_size_low],ax
- sbb [dma_size_high],0
- xor ax,ax
- mov al,[play_back_dma]
- mov bx,7
- imul bx
- add ax,offset dma_channels
- mov si,ax
- xor dx,dx
- mov dl,[si]
- mov al,[play_back_dma_mask]
- or al,4
- out dx,al
- mov al,0
- mov dl,[si+1]
- out dx,al
- mov ax,[dma_pos_low]
- mov dl,[si+2]
- out dx,al
- mov al,ah
- out dx,al
- mov ax,[dma_send]
- dec ax
- mov dl,[si+3]
- out dx,al
- mov al,ah
- out dx,al
- mov al,[play_back_dma_mask]
- or al,48h
- mov dl,[si+4]
- out dx,al
- mov al,[dma_pos_high]
- mov dl,[si+5]
- out dx,al
- mov al,[play_back_dma_mask]
- mov dl,[si+6]
- out dx,al
- pushf
- cli
- mov al,42h
- mov cx,[dram_addr]
- call write_16bit_reg
- mov dx,[gf1_register]
- mov al,41h
- out dx,al
- add dx,2
- mov al,0a9h
- mov [dma_busy],1
- out dx,al
- popf
- jmp gf1_dn
- dma_dn2: mov [dma_busy],0
- jmp gf1_dn
- no_dma2: test al,40h ; I'm not really sure why this code
- jnz no_voc ; is here, or even if it really works.
- mov al,0fh ; I've never really had a need to make
- call read_8bit_reg ; sure the voice has stopped at any
- mov [irq_source],al ; perticular time. There's just times
- and al,1fh ; when I need to know IF it's stopped.
- mov [irq_voice],al ; At any rate, I never use an IRQ for
- mov al,[irq_source] ; the end-of-voice, but it would come
- and al,0c0h ; in nice for music, so I left the
- cmp al,0c0h ; here for anyone to work with.
- jz irq_lp1
- test al,80h
- jnz no_voc
- mov al,[voice]
- mov [old_voice],al
- mov dx,[gf1_page]
- out dx,al
- mov al,0
- call read_8bit_reg
- mov [d1],al
- mov al,0dh
- call read_8bit_reg
- test [d1],4
- jnz virq_dn
- test al,4
- jnz virq_dn
- mov ax,100h
- call write_8bit_reg
- mov al,2
- call read_16bit_reg
- mov cx,ax
- mov al,0ah
- call write_16bit_reg
- mov al,3
- call read_16bit_reg
- mov cx,ax
- mov al,0bh
- call write_16bit_reg
- virq_dn: mov al,[old_voice]
- mov dx,[gf1_page]
- out dx,al
- no_voc:
-
-
- gf1_dn: mov al,20h
- out 20h,al
- pop ds dx ax
- iret
- endp gf1_ISR
-
- proc set_volume near ; ax = value (0-4095) cl = voice
- push dx
- push ax
- mov al,cl
- mov dx,[gf1_page]
- out dx,al
- pop ax
- push cx
- mov cl,4
- shl ax,cl
- mov cx,ax
- mov al,9
- call write_16bit_reg
- pop cx
- pop dx
- ret
- endp set_volume
-
- proc set_freq near ; ax = frequency of voice (0-44100) cl = voice
- push dx
- push cx
- push ax
- mov al,cl
- mov dx,[gf1_page]
- out dx,al
- pop ax
- mov bx,512
- imul bx
- mov bx,[divisor]
- shr bx,1
- add ax,bx
- adc dx,0
- mov bx,[divisor]
- div bx
- shl ax,1
- mov cx,ax
- mov al,1
- call write_16bit_reg
- pop cx
- pop dx
- ret
- endp set_freq
-
- proc set_loop near ; al = loop ctrl register (recommended value = 3)
- ; cl = voice
- push dx
- push cx
- mov dx,[gf1_page]
- mov ah,al
- mov al,cl
- out dx,al
- mov al,0dh
- call write_8bit_reg
- pop cx
- pop dx
- ret
- endp set_loop
-
- proc set_start near ; dx:ax cl = voice
- push cx
- push dx
- push ax
- mov dx,[gf1_page]
- mov al,cl
- out dx,al
- pop ax
- pop dx
- call adjust
- mov cx,ax
- mov al,3
- call write_16bit_reg
- mov al,0bh
- call write_16bit_reg
- mov cx,dx
- mov al,2
- call write_16bit_reg
- mov al,0ah
- call write_16bit_reg
- pop cx
- ret
- endp set_start
-
- proc set_end near ; dx:ax cl = voice
- push cx
- push dx
- push ax
- mov dx,[gf1_page]
- mov al,cl
- out dx,al
- pop ax
- pop dx
- call adjust
- mov cx,ax
- mov al,5
- call write_16bit_reg
- mov cx,dx
- mov al,4
- call write_16bit_reg
- pop cx
- ret
- endp set_end
-
- proc adjust near
- mov cx,9
- adj_lp1: clc
- rcl ax,1
- rcl dx,1
- loop adj_lp1
- ret
- endp adjust
-
- proc play_voice near ; al = voice ah = control register (00h = norm)
- mov bh,ah
- mov dx,[gf1_page]
- out dx,al
- inc dx
- mov al,80h
- out dx,al
- add dx,2
- in al,dx
- test al,1
- jnz voc_ok
- mov ax,300h
- call write_8bit_reg
- mov al,2
- call read_16bit_reg
- mov cx,ax
- mov al,0ah
- call write_16bit_reg
- mov al,3
- call read_16bit_reg
- mov cx,ax
- mov al,0bh
- call write_16bit_reg
- voc_ok: pushf
- cli
- mov dx,[gf1_register]
- mov al,0
- out dx,al
- and bh,5ch
- add dx,2
- mov al,bh
- out dx,al ; Let the sound begin! :)
- call delay
- out dx,al
- popf
- ret
- endp play_voice
-
- proc stop_voice near ; al = voice
- mov dx,[gf1_page]
- out dx,al
- mov ax,300h
- call write_8bit_reg
- mov al,2
- call read_16bit_reg
- mov cx,ax
- mov al,0ah
- call write_16bit_reg
- mov al,3
- call read_16bit_reg
- mov cx,ax
- mov al,0bh
- call write_16bit_reg
- ret
- endp stop_voice
-
- proc voice_status near
- mov al,0h
- call read_8bit_reg
- mov ah,0
- and al,1
- ret
- endp voice_status
-
- ends gus
- end
-
-